'''
这个文件的作用
1.读取配置文件判断安全监控使用的数据源是否是公司内部的数据源
2.如果是用的内部的数据源，那么这里就会创建定时任务，通过之前已经写好的aioodbc的api去定时更新这里缓存的数据
3.如果是用外部的数据源，那就发起请求去第三方的接口服务器上去获取。
'''
# -*- coding: utf-8 -*
import json
from tornado.gen import coroutine
from abc import ABC
from apscheduler.schedulers.tornado import TornadoScheduler

from app.configs import global_config
from app.views import SmBaseHandler
import app.service.sm_service as service
import app.service.sm_outer_service as outer_service
import app.tools.sm_config_reader as sm_type


LayerType = sm_type.LayerType
mine_id = sm_type.default_MineId
sensor_datasource_is_native = sm_type.sensor_datasource_is_native

# 缓存 全部设备的列表（表结构是原来admin视图的结构）
sm_admin_broads = None
sm_admin_videos = None
sm_admin_gass = None
# 缓存 sqlite中device表里面所有隶属于 安全监控的position
sm_device_positions = None
# 缓存 全部的设备的列表（表结构是原来data视图的结构）
sm_data_broads = None
sm_data_videos = None
sm_data_gass = None
# 缓存 设置过位置的 设备列表，原来data视图结构的
sm_selected_data_broads = None
sm_selected_data_videos = None
sm_selected_data_gass = None
# 缓存 全部设备的设备详细信息
sm_broadcast_infos = None
sm_video_infos = None
sm_gas_infos = None


current_service = service if sensor_datasource_is_native else outer_service

# 将 kj83 的m_position 同步到sqlite中
async def PositionInit():
    await service.position_init()


async def update_admin_data():
    global sm_admin_broads, sm_admin_videos, sm_admin_gass
    sm_admin_broads = await current_service.get_admin_broadcast_data()
    sm_admin_videos = await current_service.get_admin_videos_data()
    sm_admin_gass = await current_service.get_admin_sensors_data()


async def update_data_data():
    global sm_data_broads, sm_data_videos, sm_data_gass
    sm_data_broads = await current_service.get_broadcast_base_data()
    sm_data_videos = await current_service.get_video_base_data()
    # 将 admin_data中的parent_id 拼接到 传感器的data_data里面
    gas_data = await current_service.get_sensor_base_data()
    for data_gas in gas_data:
        for admin_gas in sm_admin_gass:
            if data_gas['node_id'] == admin_gas['node_id']:
                data_gas['parent_id'] = admin_gas['parent_id']
                break
    sm_data_gass =gas_data


def update_device_positions():
    global sm_device_positions
    sm_device_positions = current_service.get_sm_device_positions()


async def update_device_infos():
    global sm_broadcast_infos, sm_video_infos, sm_gas_infos
    sm_broadcast_infos = await current_service.get_broads_infos()
    sm_video_infos = await current_service.get_video_infos()
    sm_gas_infos = await current_service.get_gas_infos()


async def job():
    await update_admin_data()
    await update_data_data()
    update_device_positions()
    # 缓存 经过 筛选的 data_data
    filter_data_data()
    await update_device_infos()
    print_cache_func()


def filter_data_data():
    global sm_selected_data_gass, sm_selected_data_broads, sm_selected_data_videos
    sensor_positions = filter(lambda p : p['sub1'] == 'gas', sm_device_positions)
    broadcast_positions = filter(lambda p : p['sub1'] == 'broadcast', sm_device_positions)
    video_positions = filter(lambda p : p['sub1'] == 'video', sm_device_positions)
    selected_sensors = list()
    selected_broadcast = list()
    selected_video = list()
    for s_p in sensor_positions:
        for sensor in sm_data_gass:
            if s_p['node_id'] == sensor['node_id']:
                selected_sensors.append(sensor)
                break
    for b_p in broadcast_positions:
        for broadcast in sm_data_broads:
            if b_p['node_id'] == broadcast['node_id']:
                selected_broadcast.append(broadcast)
                break
    for v_p in video_positions:
        for video in sm_data_videos:
            if v_p['node_id'] == video['node_id']:
                selected_video.append(video)
                break
    sm_selected_data_gass = selected_sensors
    sm_selected_data_broads = selected_broadcast
    sm_selected_data_videos = selected_video



def run_cache():
    scheduler = TornadoScheduler()
    scheduler.add_job(job, 'interval', seconds=20, id="sm_cache")
    scheduler.start()


def print_cache_func():
    print('sm_admin_broads==',len(sm_admin_broads),sm_admin_broads)
    print('sm_admin_videos==',len(sm_admin_videos),sm_admin_videos)
    print('sm_admin_broads==',len(sm_admin_broads),sm_admin_broads)
    print('sm_admin_gass==',len(sm_admin_gass),sm_admin_gass)
    print('sm_device_positions==',len(sm_device_positions),sm_device_positions)
    print('sm_data_broads==',len(sm_data_broads),sm_data_broads)
    print('sm_data_videos==',len(sm_data_videos),sm_data_videos)
    print('sm_data_gass==',len(sm_data_gass),sm_data_gass)
    print('sm_selected_data_broads==',len(sm_selected_data_broads),sm_selected_data_broads)
    print('sm_selected_data_videos==',len(sm_selected_data_videos),sm_selected_data_videos)
    print('sm_selected_data_gass==',len(sm_selected_data_gass),sm_selected_data_gass)
    print('sm_broadcast_infos==',len(sm_broadcast_infos),sm_broadcast_infos)
    print('sm_video_infos==',len(sm_video_infos),sm_video_infos)
    print('sm_gas_infos==',len(sm_gas_infos),sm_gas_infos)



if 'OnePiece' == global_config['name']:
    # 缓存
    run_cache()

def broadcast_info(node_id):
    for info in sm_broadcast_infos:
        if info[0] == node_id:
            target_info = dict()
            target_info['node_id'] = info[0]
            target_info['node_type'] = info[1]
            target_info['place'] = info[2]
            target_info['layer'] = info[3]
            target_info['lastupdatetime'] = info[4].ctime()
            target_info['state'] = info[5]
            target_info['alarm'] = info[6]
    return target_info

def video_info(node_id):
    for info in sm_video_infos:
        if info[0] == node_id:
            target_info = dict()
            target_info['node_id'] = info[0]
            target_info['mine_id'] = info[1]
            target_info['parent_id'] = info[2]
            target_info['node_type'] = info[3]
            target_info['place'] = info[4]
            target_info['device_id'] = info[5]
            target_info['manufacture'] = info[6]
            target_info['ip'] = info[7]
            target_info['port'] = info[8]
            target_info['username'] = info[10]
            target_info['password'] = info[11]
            target_info['codec'] = info[12]
            target_info['channel'] = info[13]
            target_info['url'] = info[14]
            target_info['create_time'] = info[15].ctime()
    return target_info

def gas_info(node_id):
    for info in sm_gas_infos:
        if info[0] == node_id:
            target_info = dict()
            target_info['node_id'] = info[0]
            target_info['mine_id'] = info[1]
            target_info['layer'] = info[2]
            target_info['status'] = info[3]
            target_info['alarm'] = info[4]
            target_info['real_data'] = info[5]
            target_info['save_time'] = info[6].ctime()
            target_info['parent_id'] = info[7]
            target_info['node_type'] = info[8]
            target_info['unit'] = info[9]
    return target_info

functions = {
    sm_type.ServiceType["BroadCast"]: broadcast_info,
    sm_type.ServiceType["Video"]: video_info,
    sm_type.ServiceType["Gas"]:gas_info
}


class SensorAdminDataHandler(SmBaseHandler, ABC):
    @coroutine
    def get(self):
        type = self.get_query_argument('type')
        if type == 'broadcast':
            global sm_admin_broads
            self.finish({'data': sm_admin_broads})
        elif type == 'video':
            global sm_admin_videos
            self.finish({'data': sm_admin_videos})
        elif type == 'gas':
            global sm_admin_gass
            self.finish({'data': sm_admin_gass})
        else:
            pass


class SensorDataHandler(SmBaseHandler, ABC):
    @coroutine
    def get(self):
        type = self.get_query_argument('type')
        if type == 'broadcast':
            global sm_selected_data_broads
            self.finish({'data': sm_selected_data_broads})
        elif type == 'video':
            global sm_selected_data_videos
            self.finish({'data': sm_selected_data_videos})
        elif type == 'gas':
            global sm_selected_data_gass
            self.finish({'data': sm_selected_data_gass})
        else:
            pass


class SmInfoHandler(SmBaseHandler, ABC):
    @coroutine
    def get(self):
        node_id = self.get_query_argument('node_id')
        service_type = self.get_query_argument('serviceType')
        # 1.获取全部设备info信息时走下面这段
        if node_id == 'null' or service_type == 'null':
            self.finish({'broadcast_infos': sm_broadcast_infos, 'video_infos': sm_video_infos, 'gas_infos': sm_gas_infos})
        else:
            target_info = functions[service_type](node_id)
            self.finish({'data': target_info})


# 获取，编辑 sqlite中 device表格中位置信息的handler。
class SmPositionHandler(SmBaseHandler,ABC):
    @coroutine
    def get(self):
        service_type = self.get_query_argument('service_type')
        node_id = self.get_query_argument('node_id')
        if service_type == 'null' or node_id == 'null':
            # 返回全部和安全监控相关的位置信息
            self.finish({'data': sm_device_positions})
        else:
            for p in sm_device_positions:
                if p['sub1'] == service_type and p['node_id'] == node_id:
                    single_position = p
                    break
            self.finish({'data': single_position})

    @coroutine
    def post(self):
        global sm_device_positions
        positions = self.get_argument('positions')
        info = json.loads(positions)
        parts = []
        for el in info:
            t = (
                el['node_id'],
                el['service_type'],
                el['node_type'],
                el['x'],
                el['y']
            )
            parts.append(t)
        updated_device_positions = current_service.add_device_position(parts)
        # 将更新过后的 device表格中的位置信息。 同步到内存块中
        sm_device_positions = updated_device_positions
        self.finish({'data': updated_device_positions})

    @coroutine
    def put(self):
        # 批量修改位置信息，gis上拖动监控分站的时候。会同时批量修改分站下属的传感器位置
        global sm_device_positions
        positions = self.get_argument('positions')
        info = json.loads(positions)
        parts = []
        for el in info:
            t = (
                el['node_id'],
                el['service_type'],
                el['x'],
                el['y']
            )
            parts.append(t)
        sm_device_positions = current_service.update_device_position(parts)
        self.finish({'data': sm_device_positions})

    @coroutine
    def delete(self):
        global sm_device_positions
        positions = self.get_argument('positions')
        info = json.loads(positions)
        sm_device_positions = current_service.delete_device_position(info)
        self.finish({'data': sm_device_positions})


# 当数据源使用的是kj83的时候，初始化 把kj83上现有的position同步过来
class SmPositionInit(SmBaseHandler, ABC):
    async def get(self):
        await PositionInit()


